package com.badger.generator.pattern;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

import com.badger.generator.build.GeneratorController;
import com.badger.generator.build.GeneratorDataBaseExcel;
import com.badger.generator.build.GeneratorTkEntity;
import com.badger.generator.build.GeneratorMapper;
import com.badger.generator.build.GeneratorMpEntity;
import com.badger.generator.build.GeneratorService;
import com.badger.generator.build.GeneratorServicefpc;
import com.badger.generator.build.GeneratorTextFpc;
import com.badger.generator.entity.BuildResult;
import com.badger.generator.entity.GeneratorAttr;
import com.badger.generator.entity.TableAttr;
import com.badger.generator.util.BuildTextUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 代码构建的模版工厂
 * 模版工厂模式
 * @author liqi
 *
 */
@Slf4j
public final class AutoGeneratorTemplateFactory {

    private GeneratorTkEntity tkEntity;

    private GeneratorMpEntity mpEntity;

    private GeneratorMapper mapper;

    private GeneratorService service;
    
    private GeneratorServicefpc servicefpc;

    private GeneratorController controller;

    private GeneratorDataBaseExcel buildExcel;
    
    private GeneratorTextFpc textFpc;

    private List<BuildResult> resultList;

    {
        resultList = new ArrayList<>();
    }

    private AutoGeneratorTemplateFactory(GeneratorAttr attr) {
        init(attr);
    }

    private void init(GeneratorAttr attr) {
        List<TableAttr> list = ConvertSingleFactory.getInstance().buildDataBaseFactory(attr).buildTableField();
        tkEntity = new GeneratorTkEntity(attr.getAuthor(), attr.getPackagePath(), list);
        mpEntity = new GeneratorMpEntity(attr.getAuthor(), attr.getPackagePath(), list);
        mapper = new GeneratorMapper(attr.getAuthor(), attr.getPackagePath(), list);
        service = new GeneratorService(attr.getAuthor(), attr.getPackagePath(), list);
        controller = new GeneratorController(attr.getAuthor(), attr.getPackagePath(), list);
        buildExcel = new GeneratorDataBaseExcel(list);
        servicefpc= new GeneratorServicefpc(attr.getAuthor(), attr.getPackagePath(), list);
        textFpc= new GeneratorTextFpc(attr.getAuthor(), attr.getPackagePath(), list);
    }

    /**
     * 获取工厂的实例
     * @return
     */
    public static AutoGeneratorTemplateFactory getInstance(GeneratorAttr attr) {
        return new AutoGeneratorTemplateFactory(attr);
    }

    /**
     * 构建具体条件策略构建实体类
     * @param parentPath 需要继承的父级；为空，则不继承
     * @param isLombok 是否开启lombok形式
     * @param isApiModel 是否开启swagger model注解
     * @return this
     */
    public AutoGeneratorTemplateFactory buildTkModel(String parentPath, boolean isLombok, boolean isApiModel) {
        resultList.addAll(tkEntity.build(parentPath, isLombok, isApiModel));
        resultList.addAll(textFpc.buildMapperText());
        return this;
    }
    
    

    /**
     * 构建具体条件策略构建实体类
     * @param parentPath 需要继承的父级；为空，则不继承
     * @param isLombok 是否开启lombok形式
     * @param isApiModel 是否加swagger 注解
     * @param version 版本 目前有2.x以及3.x版本，导入的注解包不一样
     * @return this
     */
    public AutoGeneratorTemplateFactory buildMpModel(String parentPath, boolean isLombok, boolean isApiModel,
            String version) {
        resultList.addAll(mpEntity.build(parentPath, isLombok, isApiModel, version));
        return this;
    }

    /**
     * 构建mapper 接口和xml
     * @param parentPath 继承父类的类路径
     */
    public AutoGeneratorTemplateFactory buildMapper(String parentPath) {
        resultList.addAll(mapper.buildMapper(parentPath));
        resultList.addAll(mapper.buildMapperXml());
        return this;
    }

    /**
     * 构建service 接口以及实现的实现
     * @param serviceParent serivce父类的类路径
     * @param implParent serivceImpl父类的类路径
     */
    public AutoGeneratorTemplateFactory buildService(String serviceParent, String implParent) {
       /* resultList.addAll(service.buildService(serviceParent));
        resultList.addAll(service.buildMpServiceImpl(implParent));*/
    	
    	 resultList.addAll(servicefpc.buildService(serviceParent));
         resultList.addAll(servicefpc.buildMpServiceImpl(implParent));
        
        return this;
    }

    public AutoGeneratorTemplateFactory buildController(String parentPath) {
        resultList.addAll(controller.buildController(parentPath));
        return this;
    }

    /**
     * 把对应的文件，写入文件夹内
     * @param path
     * @return
     */
    public AutoGeneratorTemplateFactory write(final String path) {
        resultList.forEach(result -> {
            File beanFile = new File(BuildTextUtils.getFilePath(path, result.getFilePath()), result.getFileName());
            try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(beanFile)));) {
                bw.write(result.getFileContent());
                bw.flush();
                log.debug(String.format("构建文件《 %s》成功", result.getFileName()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        resultList.clear();
        return this;
    }

    public AutoGeneratorTemplateFactory openFile(final String path) {
        try {
            String osName = System.getProperty("os.name");
            if (osName != null) {
                if (osName.contains("Mac")) {
                    Runtime.getRuntime().exec("open " + path);
                } else if (osName.contains("Windows")) {
                    Runtime.getRuntime().exec("cmd /c start " + path);
                } else {
                    log.debug(String.format("文件输出目录:%s", path));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return this;
    }

    /**
     * 构建数据库excel
     * @param path excel放入的路径
     * @param fileName excel文件的名字(不带后缀)
     */
    public void buildExcel(String path, String fileName) {
        try {
            buildExcel.writeExcel(path, fileName);
            log.debug(String.format("构建excel文件《 %s》成功", fileName));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
